package gates;

import register.Register;
import mathtools.*;
import gates.MatrixGate;

/**
 * <p>AllC Not Gate - an efficient generalised Toffoli gate.</p>
 * <p>The Gate flips the target qubit if all the other qubits are 1 </p>
 * 
 * @author Jan Zaucha
 *
 */
public class AllCnotFunction extends MatrixGate {

	/** Store the target qubit the gate acts on*/	
	private int target;

	/**
	 * Protected constructor to create an instance of this object
	 * 
	 * @param target the target qubit to flip
	 */
	protected AllCnotFunction( int target){

		this.target = target+1;

	}

	/** The apply method which will allow the Gate to be appied to the Register.
	 * @param r The Quantum Register
	 */
	public void apply(Register r) {
		if (target > r.getNumQbits() || target < 1){
			throw new IllegalArgumentException("Target qubit not in register. Register size (qubits): " + r.getNumQbits() + " Target qubit: " + target);
		}
		int numStates = r.getNumStates();    // number of states in register
		// interval size- # of amplitudes in one interval of "function"
		int intervalSize = (int)(numStates/Math.pow(2,target));
		// only to states are flipped (bottom always and another one depending on target)
		Complex newAmplitude1 = r.getElement(0, numStates - 1 - intervalSize);
		Complex newAmplitude2 = r.getElement(0, numStates - 1);
		r.setElement(0, numStates - 1, newAmplitude1); /// set bottom element
		r.setElement(0, numStates - 1 - intervalSize, newAmplitude2);

	}


	/**
	 *  Return the name of the matrix.
	 */
	public String getName() {
		return "AllCnot";
	}

}
